#include "receiver.h"   // receiver.h
#include "common.h"

#define MAX_RECEIVERS 8  // 假设最多 8 个接收方
uint8_t expected_seq_num[MAX_RECEIVERS] = {0};  // 初始化为 0
#define MAX_SEQ_NUM 256 // 最大序列号

Frame *recv_buffer[MAX_RECEIVERS][MAX_SEQ_NUM] = {NULL};  // 接收缓存：按 recv_id 和 seq_num 进行索引

void init_receiver(Receiver * receiver, int id) 
{
    receiver->recv_id = id;
    receiver->input_framelist_head.next = &receiver->input_framelist_head;
    receiver->input_framelist_head.prev = &receiver->input_framelist_head;
}


void handle_incoming_msgs(Receiver * receiver)
{
    int incoming_msgs_length = ll_get_length(&receiver->input_framelist_head);
    while (incoming_msgs_length > 0)
    {
        //fprintf(stdout, "incoming_msgs_length = %d\n", incoming_msgs_length);
        //Pop a node off the front of the link list and update the count
        LLnode * ll_inmsg_node = ll_pop_node(&receiver->input_framelist_head);
        incoming_msgs_length = ll_get_length(&receiver->input_framelist_head);

        char * raw_char_buf = (char *) ll_inmsg_node->value;//将信息取出来
        Frame * inframe = convert_char_to_frame(raw_char_buf);//转化为一个帧
        //转化成frame后，buf就可以释放了
        free(raw_char_buf);
        free(ll_inmsg_node);

        // 校验帧是否损坏
        uint16_t received_checksum = inframe->checksum;
        //fprintf(stdout, "receiver received_checksum = %d\n", received_checksum);
        inframe->checksum = 0;  // 清零校验和字段，重新计算校验值
        
        //uint16_t computed_checksum = compute_crc(raw_char_buf, sizeof(Frame));
        int computed_checksum = calculate_checksum(inframe);
        //printf("********Size of Frame: %zu\n", sizeof(inframe));
        //fprintf(stderr, "我是接收方---computed_checksum = %u  received_checksum = %u \n", computed_checksum,received_checksum)

        //先判断帧的校验值，如果校验成功，则需要准备ack帧，如果校验失败，则放弃该帧，处理下一个信息 
        if (received_checksum != computed_checksum)
        {
            //fprintf(stdout, "帧损坏了,数据变成了：%s\n", inframe->data);
            free(inframe);

            continue; // 跳过损坏帧
        } 
        
        //要求接收者最后输出的信息是按序输出的，而不管中途是否发生掉包等各种问题。
        //为了提高通信效率，只要接收的帧校验ok，那就可以保存下来，后续执行按序装帧处理即可
        //先准备ack num
        // 只要收到的message frame校验ok，就需要生成并发送对应的ACK帧
        Frame *ack_frame = malloc(sizeof(Frame));
        memset(ack_frame, 0, sizeof(Frame));
        ack_frame->seq_num = 0;  // ACK 帧的序列号可以固定为 0
        ack_frame->ack_num = inframe->seq_num;  // 确认收到的帧号
        ack_frame->is_ack = 1;  // 标记为 ACK 帧
        ack_frame->recv_id = inframe->send_id;   // 设置接收方 ID
        ack_frame->send_id = receiver->recv_id;  // 设置发送方 ID
        ack_frame->checksum = 0;  // 初始化校验和字段
        ack_frame->checksum = calculate_checksum(ack_frame);  // 计算校验和
        //fprintf(stdout, "receiver send ack checksum = %d\n", ack_frame->checksum);
        char *ack_char_buf = convert_frame_to_char(ack_frame);
        
        //直接发送ack帧就好，如果会重发message frame，要么就是receiver没收到，要么就是发过去的ack 损坏，不管咋样，直接发送ack帧就好
        send_msg_to_senders(ack_char_buf); 
        //fprintf(stdout, "发送的ack帧的seq_num为：%d\n", ack_frame->ack_num);

        //将接收到的frame直接挂载到二维数组中
        if (recv_buffer[receiver->recv_id][inframe->seq_num] != NULL)
        {   //可能是ack帧损坏，导致重传，此时需要丢弃前面的frame帧，重新挂载
            free(recv_buffer[receiver->recv_id][inframe->seq_num]);
        }
        recv_buffer[receiver->recv_id][inframe->seq_num] = inframe;
        //fprintf(stdout, "接收到的帧%d带的信息为：%s\n", inframe->seq_num, inframe->data);


        free(ack_frame);
    }

}

void * run_receiver(void * input_receiver)
{    
    struct timespec   time_spec;
    struct timeval    curr_timeval;
    const int WAIT_SEC_TIME = 0;
    const long WAIT_USEC_TIME = 100000;
    Receiver * receiver = (Receiver *) input_receiver;

    //This incomplete receiver thread, at a high level, loops as follows:
    //1. Determine the next time the thread should wake up if there is nothing in the incoming queue(s)
    //2. Grab the mutex protecting the input_msg queue
    //3. Dequeues messages from the input_msg queue and prints them
    //4. Releases the lock
    //5. Sends out any outgoing messages

    pthread_cond_init(&receiver->buffer_cv, NULL);
    pthread_mutex_init(&receiver->buffer_mutex, NULL);

    while(1)
    {    
        //NOTE: Add outgoing messages to the outgoing_frames_head pointer
        gettimeofday(&curr_timeval, NULL);

        //Either timeout or get woken up because you've received a datagram
        //NOTE: You don't really need to do anything here, but it might be useful for debugging purposes to have the receivers periodically wakeup and print info
        time_spec.tv_sec  = curr_timeval.tv_sec;
        time_spec.tv_nsec = curr_timeval.tv_usec * 1000;
        time_spec.tv_sec += WAIT_SEC_TIME;
        time_spec.tv_nsec += WAIT_USEC_TIME * 1000;
        if (time_spec.tv_nsec >= 1000000000)
        {
            time_spec.tv_sec++;
            time_spec.tv_nsec -= 1000000000;
        }

        //*****************************************************************************************
        //NOTE: Anything that involves dequeing from the input frames should go 
        //      between the mutex lock and unlock, because other threads CAN/WILL access these structures
        //*****************************************************************************************
        pthread_mutex_lock(&receiver->buffer_mutex);

        //Check whether anything arrived
        int incoming_msgs_length = ll_get_length(&receiver->input_framelist_head);
        if (incoming_msgs_length == 0)
        {
            //Nothing has arrived, do a timed wait on the condition variable (which releases the mutex). Again, you don't really need to do the timed wait.
            //A signal on the condition variable will wake up the thread and reacquire the lock
            pthread_cond_timedwait(&receiver->buffer_cv, 
                                   &receiver->buffer_mutex,
                                   &time_spec);
        }

        //处理message frame，并发送相应的ack帧
        handle_incoming_msgs(receiver);

        //遍历recv_buff数组，依次打印信息
        //fprintf(stdout, "这是第%d号发送者发送的消息===============\n", receiver->recv_id);
        for (int j = expected_seq_num[receiver->recv_id]; j < MAX_SEQ_NUM; j++) {
            if (recv_buffer[receiver->recv_id][j] == NULL)
                break;
            fprintf(stdout, "<RECV-0>:[%s]\n", recv_buffer[receiver->recv_id][j]->data);
            free(recv_buffer[receiver->recv_id][j]);
            recv_buffer[receiver->recv_id][j] = NULL;
            expected_seq_num[receiver->recv_id] = (expected_seq_num[receiver->recv_id] + 1) % MAX_SEQ_NUM;
        }

        pthread_mutex_unlock(&receiver->buffer_mutex);
    }
    pthread_exit(NULL);
}
